package com.example.demo.util.excel;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class GeneralExcelPoi<T> extends AbstractExcelPoi<T> {

    private String name;

    public GeneralExcelPoi() {

    }

    public GeneralExcelPoi(String name) {
        this.name = name;
    }

    @Override
    public void doSetHead(Workbook wb, Sheet sheet, T t) {

        this.defaultHead(wb, sheet, t);

    }

    @Override
    public void doGenerateExcel(List<T> list, Sheet sheet) {
        this.defaultGenerateExcel(list, sheet);

    }

    @Override
    public void doSetCustomHead(Workbook wb, Sheet sheet, List<String> list) {
        this.customHead(wb, sheet, list);
    }

    private void customHead(Workbook wb, Sheet sheet, List<String> head) {
        Row row = sheet.createRow((short) 0);
        CellStyle blueColorStyle = getColorCellStyle(wb, IndexedColors.BLACK.getIndex(), IndexedColors.GREEN.getIndex());
        for (int i = 0; i < head.size(); i++) {
            Cell cell = getCell(sheet, row, i);
            cell.setCellValue(head.get(i));
            cell.setCellStyle(blueColorStyle);
        }
    }


    private void defaultHead(Workbook wb, Sheet sheet, T t) {

        ExcelFieldOrder excelFieldOrder = t.getClass().getAnnotation(ExcelFieldOrder.class);
        Field[] fields = t.getClass().getDeclaredFields();
        Row row = sheet.createRow((short) 0);
        CellStyle blueColorStyle = getColorCellStyle(wb, IndexedColors.BLACK.getIndex(), IndexedColors.GREEN.getIndex());
        if (isStringType(t) || isWrapperType(t)) {
            Cell cell = getCell(sheet, row, 0);
            if (StringUtils.isNotEmpty(name)) {
                cell.setCellValue(name);
            } else {
                cell.setCellValue("内容");
            }
            cell.setCellStyle(blueColorStyle);
            return;
        } else if (null != excelFieldOrder) {
            String[] values = excelFieldOrder.value();
            int i = 0;
            for (String fieldName : values) {
                Cell cell = getCell(sheet, row, i);
                Field field = ReflectionUtils.findField(t.getClass(), fieldName);
                field.setAccessible(true);
                ExcelComment excelComment = field.getAnnotation(ExcelComment.class);
                if (null != excelComment) {
                    cell.setCellValue(excelComment.value());
                } else {
                    cell.setCellValue(field.getName());
                }
                cell.setCellStyle(blueColorStyle);
                i++;
            }
        } else {
            for (int i = 0; i < fields.length; i++) {
                if (fields[i].getName().equals("this$0"))//排除内部类字段
                    continue;
                Cell cell = getCell(sheet, row, i);
                fields[i].setAccessible(true);
                ExcelComment excelComment = fields[i].getAnnotation(ExcelComment.class);
                if (null != excelComment) {
                    cell.setCellValue(excelComment.value());
                } else {
                    cell.setCellValue(fields[i].getName());
                }
                cell.setCellStyle(blueColorStyle);
            }
        }

    }

    private Cell getCell(Sheet sheet, Row row, int i) {
        sheet.setColumnWidth(i, 30 * 256);
        return row.createCell((short) i);
    }

    private void defaultGenerateExcel(List<T> list, Sheet sheet) {
        int startLine = 1;
        Field[] fields = null;
        ExcelFieldOrder excelFieldOrder = null;
        boolean firstRead = true;

        for (T t : list) {
            int j = 0;
            Row row = sheet.createRow(startLine);
            if (isStringType(t)) {
                Cell cell = row.createCell(j);
                cell.setCellValue(((String) t).intern());
            } else if (isWrapperType(t)) {
                Cell cell = row.createCell(j);
                Class<?> clazz = t.getClass();
                Field field = ReflectionUtils.findField(clazz, "value");
                ReflectionUtils.makeAccessible(field);
                cell.setCellValue(String.valueOf(ReflectionUtils.getField(field, t)));

            } else {
                if (null == excelFieldOrder && firstRead) {
                    excelFieldOrder = t.getClass().getAnnotation(ExcelFieldOrder.class);
                    firstRead = false;
                }
                if (null == fields)
                    fields = t.getClass().getDeclaredFields();

                if (null != excelFieldOrder) {
                    String[] values = excelFieldOrder.value();
                    for (String fieldName : values) {
                        Cell cell = row.createCell(j);
                        try {
                            Object object = PropertyUtils.getProperty(t, fieldName);
                            cell.setCellValue(String.valueOf(object));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                        j++;
                    }

                } else {
                    for (Field field : fields) {
                        if (field.getName().equals("this$0"))//排除内部类字段
                            continue;
                        Cell cell = row.createCell(j);
                        ReflectionUtils.makeAccessible(field);
                        cell.setCellValue(String.valueOf(ReflectionUtils.getField(field, t)));
                        j++;
                    }
                }
            }

            startLine++;
        }

    }

    private CellStyle getColorCellStyle(Workbook wb, short fontColor, short fillColor) {
        Font font = wb.createFont();
        font.setColor(fontColor);
        CellStyle cellStyle = wb.createCellStyle();
        cellStyle.setFont(font);
        cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
        cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        cellStyle.setFillForegroundColor(fillColor);
        cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellStyle.setBottomBorderColor(fontColor);
        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellStyle.setLeftBorderColor(fontColor);
        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellStyle.setRightBorderColor(fontColor);
        cellStyle.setBorderTop(CellStyle.BORDER_THIN);
        cellStyle.setTopBorderColor(fontColor);
        return cellStyle;
    }

    private boolean isStringType(T t) {
        if (t instanceof String) {
            return true;
        }
        return false;
    }

    private boolean isWrapperType(T t) {
        return getWrapperTypes().contains(t.getClass());
    }

    private Set<Class<?>> getWrapperTypes() {
        Set<Class<?>> ret = new HashSet<>();
        ret.add(Boolean.class);
        ret.add(Character.class);
        ret.add(Byte.class);
        ret.add(Short.class);
        ret.add(Integer.class);
        ret.add(Long.class);
        ret.add(Float.class);
        ret.add(Double.class);
        return ret;
    }


}